From 4e7b66791d09d2d304980b77a1048f3ce43ff9e8 Mon Sep 17 00:00:00 2001 From: Donny Bertucci Date: Fri, 1 Dec 2023 11:08:57 -0800 Subject: [PATCH 1/2] feat: add references in the article (#89) * feat: add bibtex parser * feat: successfully parse the bibtex and display it * refac: move the references to separate component * Add tabs for the preview * feat: preview * fix: add error if parse doesn't work * feat: replace cite with link * feat: style references * feat: move edit button and change download to dropdown * feat: display the references too * sh run.sh gen_api * feat: upload page add refs * sh run.sh gen_api * feat: add edit functions to refs * refac: move article editor in separate component * sh run.sh gen_api * feat: restyle so everything fits and references highlight * fix: remove base64 encoding and use raw pdb text * sh run.sh gen_api --- backend/init.sql | 12 ++-- backend/src/api_types.py | 5 +- backend/src/server.py | 40 +++++++---- frontend/package.json | 1 + frontend/src/lib/ArticleEditor.svelte | 60 ++++++++++++++++ frontend/src/lib/Markdown.svelte | 16 ++++- frontend/src/lib/References.svelte | 68 +++++++++++++++++++ frontend/src/lib/format.ts | 11 +++ frontend/src/openapi/models/EditBody.ts | 1 + frontend/src/openapi/models/ProteinEntry.ts | 1 + frontend/src/openapi/models/UploadBody.ts | 3 +- .../routes/edit/[proteinName]/+page.svelte | 42 ++++++++---- .../routes/protein/[proteinName]/+page.svelte | 59 +++++++++------- frontend/src/routes/styles.css | 20 +++++- frontend/src/routes/upload/+page.svelte | 40 +++-------- frontend/yarn.lock | 5 ++ 16 files changed, 297 insertions(+), 87 deletions(-) create mode 100644 frontend/src/lib/ArticleEditor.svelte create mode 100644 frontend/src/lib/References.svelte diff --git a/backend/init.sql b/backend/init.sql index edc4816d..37a79610 100644 --- a/backend/init.sql +++ b/backend/init.sql @@ -18,7 +18,8 @@ CREATE TABLE proteins ( name text NOT NULL UNIQUE PRIMARY KEY, -- user specified name of the protein (TODO: consider having a string limit) length integer, -- length of amino acid sequence mass numeric, -- mass in amu/daltons - content bytea -- stored markdown for the protein article (TODO: consider having a limit to how big this can be) + content bytea, -- stored markdown for the protein article (TODO: consider having a limit to how big this can be) + refs bytea -- bibtex references mentioned in the content/article ); /* @@ -45,24 +46,27 @@ CREATE TABLE species ( /* * Inserts example proteins into proteins table */ -INSERT INTO proteins (name, length, mass, content) VALUES ( +INSERT INTO proteins (name, length, mass, content, refs) VALUES ( 'Gh_comp271_c0_seq1', 0, 0.0, + null, null ); -INSERT INTO proteins (name, length, mass, content) VALUES ( +INSERT INTO proteins (name, length, mass, content, refs) VALUES ( 'Lb17_comp535_c2_seq1', 0, 0.0, + null, null ); -INSERT INTO proteins (name, length, mass, content) VALUES ( +INSERT INTO proteins (name, length, mass, content, refs) VALUES ( 'Lh14_comp2336_c0_seq1', 0, 0.0, + null, null ); diff --git a/backend/src/api_types.py b/backend/src/api_types.py index 5bd469ed..5b25eeba 100644 --- a/backend/src/api_types.py +++ b/backend/src/api_types.py @@ -28,6 +28,7 @@ class ProteinEntry(CamelModel): length: int mass: float content: str | None = None + refs: str | None = None class AllEntries(CamelModel): @@ -37,7 +38,8 @@ class AllEntries(CamelModel): class UploadBody(CamelModel): name: str content: str # markdown content from user - pdb_file_base64: str + refs: str # references used in content (bibtex form) + pdb_file_str: str class UploadError(str, enum.Enum): @@ -55,3 +57,4 @@ class EditBody(CamelModel): old_name: str # so we can identify the exact row we need to change new_name: str new_content: str | None = None + new_refs: str | None = None diff --git a/backend/src/server.py b/backend/src/server.py index fc74b0b2..ac8db09a 100644 --- a/backend/src/server.py +++ b/backend/src/server.py @@ -43,7 +43,7 @@ def get_protein_entry(protein_name: str): with Database() as db: try: entry_sql = db.execute_return( - """SELECT name, length, mass, content FROM proteins + """SELECT name, length, mass, content, refs FROM proteins WHERE name = %s""", [protein_name], ) @@ -53,13 +53,16 @@ def get_protein_entry(protein_name: str): if entry_sql is not None and len(entry_sql) != 0: # return the only entry only_returned_entry = entry_sql[0] - name, length, mass, content = only_returned_entry - # if bytes are present, decode them into a string + name, length, mass, content, refs = only_returned_entry + + # if byte arrays are present, decode them into a string if content is not None: content = bytea_to_str(content) + if refs is not None: + refs = bytea_to_str(refs) return ProteinEntry( - name=name, length=length, mass=mass, content=content + name=name, length=length, mass=mass, content=content, refs=refs ) except Exception as e: @@ -95,7 +98,7 @@ def upload_protein_entry(body: UploadBody): # if name is unique, save the pdb file and add the entry to the database try: # TODO: consider somehow sending the file as a stream instead of a b64 string or send as regular string - pdb = parse_protein_pdb(body.name, body.pdb_file_base64, encoding="b64") + pdb = parse_protein_pdb(body.name, body.pdb_file_str) except Exception: return UploadError.PARSE_ERROR @@ -107,12 +110,13 @@ def upload_protein_entry(body: UploadBody): # save to db with Database() as db: db.execute( - """INSERT INTO proteins (name, length, mass, content) VALUES (%s, %s, %s, %s);""", + """INSERT INTO proteins (name, length, mass, content, refs) VALUES (%s, %s, %s, %s, %s);""", [ pdb.name, pdb.num_amino_acids, pdb.mass_daltons, str_to_bytea(body.content), + str_to_bytea(body.refs), ], ) except Exception: @@ -133,21 +137,33 @@ def edit_protein_entry(body: EditBody): os.rename(pdb_file_name(body.old_name), pdb_file_name(body.new_name)) with Database() as db: - # if we have content/markdown, then update it, otherwise just update the name - if body.new_content is not None: + if body.new_name != body.old_name: db.execute( - """UPDATE proteins SET name = %s, content = %s WHERE name = %s""", + """UPDATE proteins SET name = %s WHERE name = %s""", [ body.new_name, + body.old_name, + ], + ) + + if body.new_content is not None: + db.execute( + """UPDATE proteins SET content = %s WHERE name = %s""", + [ str_to_bytea(body.new_content), body.old_name, ], ) - else: + + if body.new_refs is not None: db.execute( - """UPDATE proteins SET name = %s WHERE name = %s""", - [body.new_name, body.old_name], + """UPDATE proteins SET refs = %s WHERE name = %s""", + [ + str_to_bytea(body.new_refs), + body.old_name, + ], ) + except Exception: return UploadError.WRITE_ERROR diff --git a/frontend/package.json b/frontend/package.json index 6ef311e6..72df7fa1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,6 +37,7 @@ }, "type": "module", "dependencies": { + "bibtex": "^0.9.0", "marked": "^10.0.0" } } diff --git a/frontend/src/lib/ArticleEditor.svelte b/frontend/src/lib/ArticleEditor.svelte new file mode 100644 index 00000000..6b67cc05 --- /dev/null +++ b/frontend/src/lib/ArticleEditor.svelte @@ -0,0 +1,60 @@ + + + + + +
+ +