Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
printWidth: 100
trailingComma: all
13 changes: 12 additions & 1 deletion pydatalab/pydatalab/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from pydatalab.models.cells import Cell
from pydatalab.models.collections import Collection
from pydatalab.models.equipment import Equipment
from pydatalab.models.files import File
from pydatalab.models.people import Person
from pydatalab.models.samples import Sample
Expand All @@ -13,6 +14,16 @@
"samples": Sample,
"starting_materials": StartingMaterial,
"cells": Cell,
"equipment": Equipment,
}

__all__ = ("File", "Sample", "StartingMaterial", "Person", "Cell", "Collection", "ITEM_MODELS")
__all__ = (
"File",
"Sample",
"StartingMaterial",
"Person",
"Cell",
"Collection",
"Equipment",
"ITEM_MODELS",
)
20 changes: 20 additions & 0 deletions pydatalab/pydatalab/models/equipment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Optional

from pydantic import Field

from pydatalab.models.items import Item


class Equipment(Item):
"""A model for representing an experimental sample."""

type: str = Field("equipment", const="equipment", pattern="^equipment$")

serial_numbers: Optional[str]
"""A string describing one or more serial numbers for the instrument."""

manufacturer: Optional[str]
"""The manufacturer of this piece of equipment"""

location: Optional[str]
"""Place where the equipment is located"""
128 changes: 104 additions & 24 deletions pydatalab/pydatalab/routes/v0_1/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,56 @@ def dereference_files(file_ids: List[Union[str, ObjectId]]) -> Dict[str, Dict]:
return results


def get_equipment_summary():
if not current_user.is_authenticated and not CONFIG.TESTING:
return (
jsonify(
status="error",
message="Authorization required to access chemical inventory.",
),
401,
)

_project = {
"_id": 0,
"creators": {
"display_name": 1,
"contact_email": 1,
},
# "collections": {
# "collection_id": 1,
# "title": 1,
# },
"item_id": 1,
"name": 1,
"nblocks": {"$size": "$display_order"},
"characteristic_chemical_formula": 1,
"type": 1,
"date": 1,
"refcode": 1,
"location": 1,
}

items = [
doc
for doc in flask_mongo.db.items.aggregate(
[
{
"$match": {
"type": "equipment",
**get_default_permissions(user_only=False),
}
},
{"$project": _project},
]
)
]
return jsonify({"status": "success", "items": items})


get_equipment_summary.methods = ("GET",) # type: ignore


def get_starting_materials():
if not current_user.is_authenticated and not CONFIG.TESTING:
return (
Expand Down Expand Up @@ -276,7 +326,10 @@ def search_items():
if isinstance(types, str):
types = types.split(",") # should figure out how to parse as list automatically

match_obj = {"$text": {"$search": query}, **get_default_permissions(user_only=False)}
match_obj = {
"$text": {"$search": query},
**get_default_permissions(user_only=False),
}
if types is not None:
match_obj["type"] = {"$in": types}

Expand Down Expand Up @@ -360,7 +413,11 @@ def _create_sample(sample_dict: dict, copy_from_item_id: Optional[str] = None) -
sample_dict = copied_doc

elif copied_doc["type"] == "cells":
for component in ("positive_electrode", "negative_electrode", "electrolyte"):
for component in (
"positive_electrode",
"negative_electrode",
"electrolyte",
):
if copied_doc.get(component):
existing_consituent_ids = [
constituent["item"].get("item_id", None)
Expand Down Expand Up @@ -402,7 +459,10 @@ def _create_sample(sample_dict: dict, copy_from_item_id: Optional[str] = None) -
# locally for testing creator UI elements
new_sample["creator_ids"] = [24 * "0"]
new_sample["creators"] = [
{"display_name": "Public testing user", "contact_email": "[email protected]"}
{
"display_name": "Public testing user",
"contact_email": "[email protected]",
}
]
else:
new_sample["creator_ids"] = [current_user.person.immutable_id]
Expand Down Expand Up @@ -458,29 +518,36 @@ def _create_sample(sample_dict: dict, copy_from_item_id: Optional[str] = None) -
400,
)

sample_list_entry = {
"refcode": data_model.refcode,
"item_id": data_model.item_id,
"nblocks": 0,
"date": data_model.date,
"name": data_model.name,
"creator_ids": data_model.creator_ids,
# TODO: This workaround for creators & collections is still gross, need to figure this out properly
"creators": [json.loads(c.json(exclude_unset=True)) for c in data_model.creators]
if data_model.creators
else [],
"collections": [
json.loads(c.json(exclude_unset=True, exclude_none=True))
for c in data_model.collections
]
if data_model.collections
else [],
"type": data_model.type,
}

# hack to let us use _create_sample() for equipment too. We probably want to make
# a more general create_item() to more elegantly handle different returns.
if data_model.type == "equipment":
sample_list_entry["location"] = data_model.location

data = (
{
"status": "success",
"item_id": data_model.item_id,
"sample_list_entry": {
"refcode": data_model.refcode,
"item_id": data_model.item_id,
"nblocks": 0,
"date": data_model.date,
"name": data_model.name,
"creator_ids": data_model.creator_ids,
# TODO: This workaround for creators & collections is still gross, need to figure this out properly
"creators": [json.loads(c.json(exclude_unset=True)) for c in data_model.creators]
if data_model.creators
else [],
"collections": [
json.loads(c.json(exclude_unset=True, exclude_none=True))
for c in data_model.collections
]
if data_model.collections
else [],
"type": data_model.type,
},
"sample_list_entry": sample_list_entry,
},
201, # 201: Created
)
Expand Down Expand Up @@ -585,7 +652,12 @@ def get_item_data(item_id, load_blocks: bool = False):
# retrieve the entry from the database:
cursor = flask_mongo.db.items.aggregate(
[
{"$match": {"item_id": item_id, **get_default_permissions(user_only=False)}},
{
"$match": {
"item_id": item_id,
**get_default_permissions(user_only=False),
}
},
{"$lookup": creators_lookup()},
{"$lookup": collections_lookup()},
{"$lookup": files_lookup()},
Expand Down Expand Up @@ -708,7 +780,14 @@ def save_item():
updated_data = request_json["data"]

# These keys should not be updated here and cannot be modified by the user through this endpoint
for k in ("_id", "file_ObjectIds", "creators", "creator_ids", "item_id", "relationships"):
for k in (
"_id",
"file_ObjectIds",
"creators",
"creator_ids",
"item_id",
"relationships",
):
if k in updated_data:
del updated_data[k]

Expand Down Expand Up @@ -827,6 +906,7 @@ def search_users():
ENDPOINTS: Dict[str, Callable] = {
"/samples/": get_samples,
"/starting-materials/": get_starting_materials,
"/equipment/": get_equipment_summary,
"/search-items/": search_items,
"/search-users/": search_users,
"/new-sample/": create_sample,
Expand Down
4 changes: 2 additions & 2 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
"cypress": "^13.6.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^8.0.3",
"prettier": "^2.4.1",
"prettier": "3.0.3",
"typescript": "~3.9.3",
"web-worker": "^1.2.0"
}
Expand Down
Loading