From c98d6a0f2e8df7eb6c884c42f0c8dfe2c1badb58 Mon Sep 17 00:00:00 2001 From: MooGoo Date: Tue, 14 May 2024 02:36:20 +0800 Subject: [PATCH] fix: admin-record many bugs --- app/blueprints/admin.py | 46 +++-- app/blueprints/api.py | 8 +- app/database.py | 11 +- app/helpers.py | 21 ++- app/models/collection.py | 3 +- app/templates/admin/record-list-view.html | 9 + client/admin-record/src/App.svelte | 209 +++++++++++++++------- 7 files changed, 218 insertions(+), 89 deletions(-) diff --git a/app/blueprints/admin.py b/app/blueprints/admin.py index b52377b..f3622e3 100644 --- a/app/blueprints/admin.py +++ b/app/blueprints/admin.py @@ -87,7 +87,7 @@ def check_auth(): def save_record(record, payload, collection): #print(record, payload, flush=True) - is_debug = True + is_debug = False uid = payload.get('uid') is_new_record = False @@ -153,9 +153,9 @@ def save_record(record, payload, collection): new_val = selected['value'] if name in pv: if pv[name].value != new_val: - - pv[name].value = new_val changes[name] = ['UPDATE', pv[name].value, new_val] + pv[name].value = new_val + else: if a_type := AssertionType.query.filter(AssertionType.name==name).first(): new_ra = RecordAssertion(record_id=record.id, assertion_type_id=a_type.id, value=new_val) @@ -201,7 +201,10 @@ def save_record(record, payload, collection): iden_modify = make_editable_values(iden, i) if len(iden_modify): iden.update(iden_modify) - changes[iden.id] = iden_modify + iden_changes = inspect_model(iden) + if len(iden_changes): + changes[iden.id] = iden_changes + if len(changes): relate_changes['identifications'] = changes @@ -233,7 +236,9 @@ def save_record(record, payload, collection): unit_modify = make_editable_values(unit, i) if len(unit_modify): unit.update(unit_modify) - changes[unit.id] = unit_modify + unit_changes = inspect_model(unit) + if len(unit_changes): + changes[unit.id] = unit_changes if assertions := i.get('assertions'): changes_assertions = {} @@ -248,12 +253,12 @@ def save_record(record, payload, collection): # update pure_value = v if assertion_type_map[k].input_type == 'select': - # print(v, '---',flush=True) if isinstance(v, dict): pure_value = v.get('value') - pv_assertions[k].value = pure_value - #print('update', k, pure_value, flush=True) - changes_assertions[k] = ['UPDATE', k, pv_assertions[k].value, pure_value] + if pv_assertions[k].value != pure_value: + pv_assertions[k].value = pure_value + #print('update', k, pure_value, flush=True) + changes_assertions[k] = ['UPDATE', k, pv_assertions[k].value, pure_value] else: # delete session.delete(pv_assertions[k]) @@ -266,7 +271,10 @@ def save_record(record, payload, collection): session.add(a) #print('insert', k, flush=True) changes_assertions[k] = ['CREATE', k, v] - changes[unit.id]['assertions'] = changes_assertions + if len(changes_assertions): + if unit.id not in changes: + changes[unit.id] = {} + changes[unit.id]['assertions'] = changes_assertions if annotations := i.get('annotations'): changes_annotations = {} @@ -299,7 +307,10 @@ def save_record(record, payload, collection): session.add(a) #print('insert', k, flush=True) changes_annotations[k] = ['CREATE', k, v] - changes[unit.id]['annotations'] = changes_annotations + if len(changes_annotations): + if unit.id not in changes: + changes[unit.id] = {} + changes[unit.id]['annotations'] = changes_annotations if len(changes): relate_changes['units'] = changes @@ -627,7 +638,7 @@ def record_list(): cat_lists= UserList.query.filter(UserList.user_id==current_user.id, UserList.entity_id==entity_id).all() - print(r, flush=True) + #print(r, flush=True) item = { 'collection_id': r[11], 'accession_number': r[1] or '', @@ -644,11 +655,20 @@ def record_list(): } items.append(item) + plist = Person.query.filter(Person.is_collector==True).all() + collector_list = [{ + 'id': x.id, + 'full_name': x.full_name, + 'full_name_en': x.full_name_en, + 'display_name': x.display_name, + } for x in plist] return render_template( 'admin/record-list-view.html', items=items, total=total, - pagination=pagination) + pagination=pagination, + collector_list=collector_list, + ) @admin.route('//records/create', methods=['GET', 'POST']) diff --git a/app/blueprints/api.py b/app/blueprints/api.py index 732da9d..a82a330 100644 --- a/app/blueprints/api.py +++ b/app/blueprints/api.py @@ -51,8 +51,6 @@ AssertionType, Collection, MultimediaObject, - #LogEntry, - #get_structed_list, ) from app.models.gazetter import ( NamedArea, @@ -875,12 +873,14 @@ def api_create_admin_record(collection_id): res.headers['Access-Control-Allow-Headers'] = 'Content-Type' return res elif request.method == 'POST': - record, is_new = save_record(None, request.json, collection_id) + if col := session.get(Collection, collection_id): + record, is_new = save_record(None, request.json, col) if is_new: + uid = request.json.get('uid') return jsonify({ 'message': 'ok', - 'next': url_for('admin.modify_frontend_collection_record', collection_id=record.collection_id, record_id=record.id), + 'next': url_for('admin.modify_frontend_collection_record', collection_id=record.collection_id, record_id=record.id)+f'?uid={uid}', }) else: return jsonify({'message': 'ok'}) diff --git a/app/database.py b/app/database.py index 054419c..f331c82 100644 --- a/app/database.py +++ b/app/database.py @@ -7,9 +7,14 @@ Column, String, DateTime, - ForeignKey + ForeignKey, +) +from sqlalchemy.orm import ( + scoped_session, + sessionmaker, + Session, + relationship, ) -from sqlalchemy.orm import scoped_session, sessionmaker, Session from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.dialects.postgresql import JSONB @@ -99,3 +104,5 @@ class ModelHistory(Base): changes = Column(JSONB) created = Column(DateTime, default=get_time) remarks = Column(String(500)) + + user = relationship('User') diff --git a/app/helpers.py b/app/helpers.py index 5b9ec64..3c304b5 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -7,8 +7,12 @@ ) from sqlalchemy import( inspect, + desc, +) +from app.database import ( + session, + ModelHistory, ) -from app.database import session from app.models.site import Organization from app.models.collection import ( Collection, @@ -178,7 +182,20 @@ def get_record_values(record): if x.named_area.area_class_id in [5, 6] or x.named_area.area_class_id >= 7: data['named_areas'][x.named_area.area_class.name] = x.named_area.to_dict() - data['named_areas__legacy'] = [x.to_dict() for x in record.get_named_area_list('legacy')], + data['named_areas__legacy'] = [x.to_dict() for x in record.get_named_area_list('legacy')] + + histories = ModelHistory.query.filter(ModelHistory.tablename=='record*', ModelHistory.item_id==str(record.id)).order_by(desc(ModelHistory.created)).all() + data['__histories__'] = [{ + 'id': x.id, + 'changes': x.changes, + 'action': x.action, + 'created': x.created.strftime('%Y-%m-%d %H:%M:%S'), + 'user': { + 'username': x.user.username, + 'uid': x.user_id, + } + } for x in histories] + return data def make_editable_values(model, data): diff --git a/app/models/collection.py b/app/models/collection.py index ee2d70b..bc79815 100644 --- a/app/models/collection.py +++ b/app/models/collection.py @@ -959,8 +959,7 @@ def get_editable_fields(field_types=['date', 'str', 'bool']): 'kind_of_unit', 'preparation_type', 'preservation_text', - 'acquisition_type' - 'acquired_from', + 'acquisition_type', 'acquisition_source_text', 'type_status', 'typified_name', diff --git a/app/templates/admin/record-list-view.html b/app/templates/admin/record-list-view.html index 47e5b57..faec66f 100644 --- a/app/templates/admin/record-list-view.html +++ b/app/templates/admin/record-list-view.html @@ -19,6 +19,15 @@
keyword: 館號、物種、採集者、採集號
+
+ +
+ + +
    +
  • aeu
  • +
+

Results: {{ "{:,}".format(total) }}

diff --git a/client/admin-record/src/App.svelte b/client/admin-record/src/App.svelte index e0d5c59..d7e4170 100644 --- a/client/admin-record/src/App.svelte +++ b/client/admin-record/src/App.svelte @@ -11,6 +11,8 @@ let formValues = { uid: $allOptions.current_user.uid, }; + let initValues = {}; + let touched = {}; let fetchOptions = { identificationTaxon: [], @@ -143,8 +145,8 @@ } }); - const init = async () => { - touched.field_number = false; + const initUpdate = async () => { + initValues = {...$values}; // apply data formValues.project = $values.project; formValues.field_number = $values.field_number; @@ -219,17 +221,46 @@ value: data.id, }; } - }; // end of init + }; // end of initUpdate + + const initNew = () => { + // apply data + initValues.project = null; + initValues.field_number = null; + initValues.collect_date = null; + initValues.collect_date_text = null; + initValues.verbatim_collector = null; + initValues.companion_text = null; + initValues.companion_text_en = null; + initValues.field_note = null; + initValues.field_note_en = null; + initValues.longitude_decimal = null; + initValues.latitude_decimal = null; + initValues.verbatim_latitude = null; + initValues.verbatim_longitude = null; + initValues.verbatim_locality = null; + initValues.locality_text = null; + initValues.locality_text_en = null; + initValues.altitude = null; + initValues.altitude2 = null; + initValues.collector = null; + initValues.assertions = {}; + //initValues.units = []; + //initValues.identifications = []; + initValues.named_areas = {}; + + formValues.assertions = {}; + //formValues.units = []; + //formValues.identifications = []; + formValues.named_areas = {}; + }; // end of initNew if ($values) { - init(); + initUpdate(); } else if ($hasError) { alert($hasError); } else { - formValues.assertions = {}; - formValues.units = []; - formValues.identifications = []; - formValues.named_areas = []; + initNew(); } console.log($allOptions, $values, formValues); @@ -445,9 +476,11 @@ const addIdentification = () => { let seq = formValues.identifications.length + 1; + console.log(seq); formValues.identifications = [...formValues.identifications, {sequence: seq}]; + /* fetchOptions.identificationTaxon.push([]); - fetchLoading.identificationTaxon.push(false); + fetchLoading.identificationTaxon.push(false);*/ } const syncLongitudeDecimal = (e) => { @@ -474,7 +507,8 @@ } // HACK, taiwan and china has adm3 - $: if (formValues.named_areas.COUNTRY + $: if (formValues.named_areas + && formValues.named_areas.COUNTRY && [1311, 1358].indexOf(formValues.named_areas.COUNTRY.value) >= 0) { hasNamedAreaAdmin3 = true; } else { @@ -482,9 +516,11 @@ } const getDisplayNamedAreaAdmin = (namedAreas) => { let naList = []; - for (let key of ['COUNTRY', 'ADM1', 'ADM2', 'ADM3']) { - if (key in namedAreas && namedAreas[key]?.value) { - naList.push(namedAreas[key].text); + if (namedAreas) { + for (let key of ['COUNTRY', 'ADM1', 'ADM2', 'ADM3']) { + if (key in namedAreas && namedAreas[key]?.value) { + naList.push(namedAreas[key].text); + } } } return naList.join(' ,'); @@ -532,40 +568,40 @@ formValues.collector = selected; }} onClear={()=>{formValues.collector=null;}} - initValue={$values.collector?.id} + initValue={initValues.collector?.id} />
- +
- +
- +
- +
- +
- +
- +
- +
@@ -576,19 +612,19 @@
- +
- +
- +
- +
- +
@@ -743,7 +779,7 @@ onSelect={(x) => handleNamedAreaAdminSelect(x, 'COUNTRY')} value={formValues.named_areas.COUNTRY} onClear={() => {handleNamedAreaAdminClear('COUNTRY')}} - initValue={$values.named_areas.COUNTRY?.id} + initValue={initValues.named_areas.COUNTRY?.id} /> @@ -762,7 +798,7 @@ onSelect={(x) => handleNamedAreaAdminSelect(x, 'ADM1')} value={formValues.named_areas.ADM1} onClear={() => {handleNamedAreaAdminClear('ADM1')}} - initValue={$values.named_areas.ADM1?.id} + initValue={initValues.named_areas.ADM1?.id} /> @@ -781,7 +817,7 @@ onSelect={(x) => {handleNamedAreaAdminSelect(x, 'ADM2')}} value={formValues.named_areas.ADM2} onClear={() => {handleNamedAreaAdminClear('ADM2')}} - initValue={$values.named_areas.ADM2?.id} + initValue={initValues.named_areas.ADM2?.id} /> @@ -801,7 +837,7 @@ onSelect={(x) => {handleNamedAreaAdminSelect(x, 'ADM3')}} value={formValues.named_areas.ADM3} onClear={ () => {formValues.named_areas.ADM3 = null;}} - initValue={$values.named_areas.ADM3?.id} + initValue={initValues.named_areas.ADM3?.id} /> @@ -865,7 +901,7 @@ formValues.named_areas[name] = selected; }} onClear={()=>{formValues.named_areas[name] = null;}} - initValue={$values.named_areas[name]?.id} + initValue={initValues.named_areas[name]?.id} /> @@ -874,13 +910,13 @@ {/each}
- +
- +
- +
@@ -904,7 +940,7 @@ formValues.assertions[data.name] = selected; }} onClear={()=>{formValues.assertions[data.name]=null;}} - initValue={$values.assertions[data.name]} + initValue={initValues.assertions[data.name]} /> @@ -920,7 +956,7 @@ 資料
- ({text: x.name, value: x.id}))} initValue={$values.project}/> + ({text: x.name, value: x.id}))} initValue={initValues.project}/>
@@ -928,6 +964,7 @@
+ {#if $values}
鑑定 @@ -941,7 +978,7 @@ - +
@@ -958,7 +995,7 @@ }} value={idObj.taxon} onInput={(input) => onIdentificationTaxonInput(input, idx)} - initValue={(idx < $values.identifications.length) ? $values.identifications[idx].taxon?.id: null} + initValue={(idx < initValues.identifications.length) ? initValues.identifications[idx].taxon?.id: null} /> @@ -976,16 +1013,16 @@ }} value={idObj.identifier} onClear={()=>{idObj.identifier=null;}} - initValue={(idx < $values.identifications.length) ? $values.identifications[idx].identifier?.id: null} + initValue={(idx < initValues.identifications.length) ? initValues.identifications[idx].identifier?.id: null} />
- +
- +
@@ -997,6 +1034,8 @@ + {/if} + {#if $values}
標本 @@ -1015,10 +1054,10 @@ {#each formValues.units as unit, idx} - + - +