From d2d89ae4220e67b8ffa418c08610d15e1f531653 Mon Sep 17 00:00:00 2001
From: pcain-usgs <pcain@usgs.gov>
Date: Thu, 8 Apr 2021 12:08:06 -0600
Subject: [PATCH] database for factory __init__, remove reviewed, remove delete
 endpoint

---
 geomagio/api/db/MetadataDatabaseFactory.py | 90 ++++++++++------------
 geomagio/api/db/metadata_table.py          |  3 -
 geomagio/api/secure/metadata.py            | 29 +++----
 geomagio/api/ws/metadata.py                |  5 +-
 geomagio/metadata/Metadata.py              |  2 -
 geomagio/metadata/MetadataFactory.py       |  9 ---
 geomagio/metadata/MetadataQuery.py         |  1 -
 geomagio/metadata/main.py                  | 20 -----
 test_metadata.py                           |  2 +-
 9 files changed, 53 insertions(+), 108 deletions(-)

diff --git a/geomagio/api/db/MetadataDatabaseFactory.py b/geomagio/api/db/MetadataDatabaseFactory.py
index d221c4de4..89475eb33 100644
--- a/geomagio/api/db/MetadataDatabaseFactory.py
+++ b/geomagio/api/db/MetadataDatabaseFactory.py
@@ -1,35 +1,24 @@
 from datetime import datetime
 from typing import List
 
+from databases import Database
 from obspy import UTCDateTime
-from sqlalchemy import or_, Table
+from sqlalchemy import or_
 
 from ...metadata import Metadata, MetadataCategory
-from .common import database
 from .metadata_history_table import metadata_history
 from .metadata_table import metadata
 
 
 class MetadataDatabaseFactory(object):
-    def __init__(
-        self, table: Table = metadata, history_table: Table = metadata_history
-    ):
-        self.table = table
-        self.history_table = history_table
+    def __init__(self, database: Database):
+        self.database = database
 
     async def create_metadata(self, meta: Metadata) -> Metadata:
         query = metadata.insert()
         values = meta.datetime_dict(exclude={"id", "metadata_id"}, exclude_none=True)
         query = query.values(**values)
-        meta.id = await database.execute(query)
-        return meta
-
-    async def create_metadata_history(self, meta: Metadata) -> Metadata:
-        query = self.history_table.insert()
-        meta.metadata_id = meta.id
-        values = meta.datetime_dict(exclude={"id"}, exclude_none=True)
-        query = query.values(**values)
-        meta.id = await database.execute(query)
+        meta.id = await self.database.execute(query)
         return meta
 
     async def get_metadata(
@@ -47,50 +36,46 @@ class MetadataDatabaseFactory(object):
         created_before: datetime = None,
         data_valid: bool = None,
         metadata_valid: bool = None,
-        reviewed: bool = None,
         status: str = None,
     ):
-        table = self.table
-        query = table.select()
+        query = metadata.select()
         if id:
-            query = query.where(table.c.id == id)
+            query = query.where(metadata.c.id == id)
         if category:
-            query = query.where(table.c.category == category)
+            query = query.where(metadata.c.category == category)
         if network:
-            query = query.where(table.c.network == network)
+            query = query.where(metadata.c.network == network)
         if station:
-            query = query.where(table.c.station == station)
+            query = query.where(metadata.c.station == station)
         if channel:
-            query = query.where(table.c.channel.like(channel))
+            query = query.where(metadata.c.channel.like(channel))
         if location:
-            query = query.where(table.c.location.like(location))
+            query = query.where(metadata.c.location.like(location))
         if starttime:
             query = query.where(
                 or_(
-                    table.c.endtime == None,
-                    table.c.endtime > starttime,
+                    metadata.c.endtime == None,
+                    metadata.c.endtime > starttime,
                 )
             )
         if endtime:
             query = query.where(
                 or_(
-                    table.c.starttime == None,
-                    table.c.starttime < endtime,
+                    metadata.c.starttime == None,
+                    metadata.c.starttime < endtime,
                 )
             )
         if created_after:
-            query = query.where(table.c.created_time > created_after)
+            query = query.where(metadata.c.created_time > created_after)
         if created_before:
-            query = query.where(table.c.created_time < created_before)
+            query = query.where(metadata.c.created_time < created_before)
         if data_valid is not None:
-            query = query.where(table.c.data_valid == data_valid)
+            query = query.where(metadata.c.data_valid == data_valid)
         if metadata_valid is not None:
-            query = query.where(table.c.metadata_valid == metadata_valid)
-        if reviewed is not None:
-            query = query.where(table.c.reviewed == reviewed)
+            query = query.where(metadata.c.metadata_valid == metadata_valid)
         if status is not None:
-            query = query.where(table.c.status == status)
-        rows = await database.fetch_all(query)
+            query = query.where(metadata.c.status == status)
+        rows = await self.database.fetch_all(query)
         return [Metadata(**row) for row in rows]
 
     async def get_metadata_by_id(self, id: int):
@@ -100,27 +85,32 @@ class MetadataDatabaseFactory(object):
         return meta[0]
 
     async def get_metadata_history(self, metadata_id: int) -> List[Metadata]:
-        query = self.history_table.select()
-        query = query.where(self.history_table.c.metadata_id == metadata_id)
-        rows = await database.fetch_all(query)
+        query = metadata_history.select()
+        query = query.where(metadata_history.c.metadata_id == metadata_id).order_by(
+            metadata_history.c.updated_time
+        )
+        rows = await self.database.fetch_all(query)
         metadata = [Metadata(**row) for row in rows]
         current_metadata = await self.get_metadata_by_id(id=metadata_id)
         metadata.append(current_metadata)
-        # return records in order of age
+        # return records in order of age(newest first)
         metadata.reverse()
         return metadata
 
-    async def update_metadata(
-        self, meta: Metadata, username: str, status: str = None
-    ) -> Metadata:
-        async with database.transaction() as transaction:
+    async def update_metadata(self, meta: Metadata, updated_by: str) -> Metadata:
+        async with self.database.transaction() as transaction:
+            # write current record to metadata history table
             original_metadata = await self.get_metadata_by_id(id=meta.id)
-            await self.create_metadata_history(meta=original_metadata)
-            meta.updated_by = username
+            query = metadata_history.insert()
+            original_metadata.metadata_id = original_metadata.id
+            values = original_metadata.datetime_dict(exclude={"id"}, exclude_none=True)
+            query = query.values(**values)
+            original_metadata.id = await self.database.execute(query)
+            # update record in metadata table
+            meta.updated_by = updated_by
             meta.updated_time = UTCDateTime()
-            meta.status = status or meta.status
-            query = self.table.update().where(self.table.c.id == meta.id)
+            query = metadata.update().where(metadata.c.id == meta.id)
             values = meta.datetime_dict(exclude={"id", "metadata_id"})
             query = query.values(**values)
-            await database.execute(query)
+            await self.database.execute(query)
         return await self.get_metadata_by_id(id=meta.id)
diff --git a/geomagio/api/db/metadata_table.py b/geomagio/api/db/metadata_table.py
index c80567828..e55e66878 100644
--- a/geomagio/api/db/metadata_table.py
+++ b/geomagio/api/db/metadata_table.py
@@ -40,8 +40,6 @@ metadata = Table(
     Column("data_valid", Boolean, default=True, index=True),
     # whether metadata is valid (based on review)
     Column("metadata_valid", Boolean, default=True, index=True),
-    # whether metadata has been reviewed
-    Column("reviewed", Boolean, default=True, index=True),
     # deletion status indicator
     Column("status", String(length=255), nullable=True),
     # metadata json blob
@@ -66,7 +64,6 @@ metadata = Table(
         # valid
         "metadata_valid",
         "data_valid",
-        "reviewed",
         "status",
     ),
     Index(
diff --git a/geomagio/api/secure/metadata.py b/geomagio/api/secure/metadata.py
index baf4094a0..d397faca1 100644
--- a/geomagio/api/secure/metadata.py
+++ b/geomagio/api/secure/metadata.py
@@ -21,6 +21,7 @@ from obspy import UTCDateTime
 
 from ...metadata import Metadata, MetadataCategory, MetadataQuery
 from ... import pydantic_utcdatetime
+from ..db.common import database
 from ..db import MetadataDatabaseFactory
 from .login import require_user, User
 
@@ -34,19 +35,10 @@ async def create_metadata(
     metadata: Metadata,
     user: User = Depends(require_user()),
 ):
-    metadata = await MetadataDatabaseFactory().create_metadata(meta=metadata)
-    return Response(metadata.json(), status_code=201, media_type="application/json")
-
-
-@router.delete("/metadata/{id}")
-async def delete_metadata(
-    id: int, user: User = Depends(require_user([os.getenv("ADMIN_GROUP", "admin")]))
-):
-    database_factory = MetadataDatabaseFactory()
-    metadata = await database_factory.get_metadata_by_id(id=id)
-    await database_factory.update_metadata(
-        meta=metadata, username=user.nickname, status="deleted"
+    metadata = await MetadataDatabaseFactory(database=database).create_metadata(
+        meta=metadata
     )
+    return Response(metadata.json(), status_code=201, media_type="application/json")
 
 
 @router.get("/metadata", response_model=List[Metadata])
@@ -62,7 +54,6 @@ async def get_metadata(
     location: str = None,
     data_valid: bool = None,
     metadata_valid: bool = True,
-    reviewed: bool = None,
     status: str = None,
 ):
     query = MetadataQuery(
@@ -77,10 +68,9 @@ async def get_metadata(
         location=location,
         data_valid=data_valid,
         metadata_valid=metadata_valid,
-        reviewed=reviewed,
         status=status,
     )
-    metas = await MetadataDatabaseFactory().get_metadata(
+    metas = await MetadataDatabaseFactory(database=database).get_metadata(
         **query.datetime_dict(exclude={"id", "metadata_id"})
     )
     return metas
@@ -88,14 +78,14 @@ async def get_metadata(
 
 @router.get("/metadata/{id}", response_model=Metadata)
 async def get_metadata_by_id(id: int):
-    return await MetadataDatabaseFactory().get_metadata_by_id(id=id)
+    return await MetadataDatabaseFactory(database=database).get_metadata_by_id(id=id)
 
 
 @router.get("/metadata/{metadata_id}/history", response_model=List[Metadata])
 async def get_metadata_history(
     metadata_id: int,
 ):
-    return await MetadataDatabaseFactory().get_metadata_history(
+    return await MetadataDatabaseFactory(database=database).get_metadata_history(
         metadata_id=metadata_id,
     )
 
@@ -106,6 +96,7 @@ async def update_metadata(
     metadata: Metadata = Body(...),
     user: User = Depends(require_user([os.getenv("REVIEWER_GROUP", "reviewer")])),
 ):
-    return await MetadataDatabaseFactory().update_metadata(
-        meta=metadata, username=user.nickname
+    return await MetadataDatabaseFactory(database=database).update_metadata(
+        meta=metadata,
+        updated_by=user.nickname,
     )
diff --git a/geomagio/api/ws/metadata.py b/geomagio/api/ws/metadata.py
index 57b89cb30..1dc77ee2c 100644
--- a/geomagio/api/ws/metadata.py
+++ b/geomagio/api/ws/metadata.py
@@ -4,6 +4,7 @@ from fastapi import APIRouter
 from obspy import UTCDateTime
 
 from ...metadata import Metadata, MetadataCategory, MetadataQuery
+from ..db.common import database
 from ..db import MetadataDatabaseFactory
 
 router = APIRouter()
@@ -20,7 +21,6 @@ async def get_metadata(
     location: str = None,
     data_valid: bool = None,
     metadata_valid: bool = True,
-    reviewed: bool = None,
     status: str = None,
 ):
     query = MetadataQuery(
@@ -33,10 +33,9 @@ async def get_metadata(
         location=location,
         data_valid=data_valid,
         metadata_valid=metadata_valid,
-        reviewed=reviewed,
         status=status,
     )
-    metas = await MetadataDatabaseFactory().get_metadata(
+    metas = await MetadataDatabaseFactory(database=database).get_metadata(
         **query.datetime_dict(exclude={"id"})
     )
     return metas
diff --git a/geomagio/metadata/Metadata.py b/geomagio/metadata/Metadata.py
index b6bcb6ba0..dff97fbeb 100644
--- a/geomagio/metadata/Metadata.py
+++ b/geomagio/metadata/Metadata.py
@@ -72,8 +72,6 @@ class Metadata(BaseModel):
     data_valid: bool = True
     # whether metadata is valid (based on review)
     metadata_valid: bool = True
-    # whether metadata has been reviewed
-    reviewed: bool = False
     # metadata json blob
     metadata: Dict = None
     # general comment
diff --git a/geomagio/metadata/MetadataFactory.py b/geomagio/metadata/MetadataFactory.py
index 0558bcc20..e000c887f 100644
--- a/geomagio/metadata/MetadataFactory.py
+++ b/geomagio/metadata/MetadataFactory.py
@@ -27,15 +27,6 @@ class MetadataFactory(object):
     def _get_headers(self):
         return {"Authorization": self.token} if self.token else None
 
-    def delete_metadata(self, metadata: Metadata) -> bool:
-        response = requests.delete(
-            url=f"{self.url}/{metadata.id}",
-            headers=self._get_headers(),
-        )
-        if response.status_code == 200:
-            return True
-        return False
-
     def get_metadata(self, query: MetadataQuery) -> List[Metadata]:
         if query.id:
             metadata = [self.get_metadata_by_id(id=query.id)]
diff --git a/geomagio/metadata/MetadataQuery.py b/geomagio/metadata/MetadataQuery.py
index 025c000b7..5b5214849 100644
--- a/geomagio/metadata/MetadataQuery.py
+++ b/geomagio/metadata/MetadataQuery.py
@@ -21,7 +21,6 @@ class MetadataQuery(BaseModel):
     location: str = None
     data_valid: Optional[bool] = None
     metadata_valid: Optional[bool] = None
-    reviewed: Optional[bool] = None
     status: Optional[str] = None
 
     def datetime_dict(self, **kwargs):
diff --git a/geomagio/metadata/main.py b/geomagio/metadata/main.py
index 1b7c8da81..69e8eeecc 100644
--- a/geomagio/metadata/main.py
+++ b/geomagio/metadata/main.py
@@ -110,24 +110,6 @@ def create(
     print(metadata.json())
 
 
-@app.command(
-    help=f"""
-    Delete an existing metadata.
-
-    {ENVIRONMENT_VARIABLE_HELP}
-    """
-)
-def delete(
-    input_file: str,
-    url: str = GEOMAG_API_URL,
-):
-    metadata_dict = load_metadata(input_file=input_file)
-    metadata = Metadata(**metadata_dict)
-    deleted = MetadataFactory(url=url).delete_metadata(metadata=metadata)
-    if not deleted:
-        sys.exit(1)
-
-
 @app.command(
     help=f"""
     Search existing metadata.
@@ -147,7 +129,6 @@ def get(
     location: Optional[str] = None,
     metadata_valid: Optional[bool] = None,
     network: Optional[str] = None,
-    reviewed: Optional[bool] = None,
     status: Optional[str] = None,
     starttime: Optional[str] = None,
     station: Optional[str] = None,
@@ -164,7 +145,6 @@ def get(
         location=location,
         metadata_valid=metadata_valid,
         network=network,
-        reviewed=reviewed,
         starttime=UTCDateTime(starttime) if starttime else None,
         station=station,
         status=status,
diff --git a/test_metadata.py b/test_metadata.py
index 27403f9b9..1a78b1bcf 100644
--- a/test_metadata.py
+++ b/test_metadata.py
@@ -176,7 +176,7 @@ test_metadata.append(
 async def load_test_metadata():
     await database.connect()
     for meta in test_metadata:
-        await MetadataDatabaseFactory().create_metadata(meta)
+        await MetadataDatabaseFactory(database=database).create_metadata(meta)
     await database.disconnect()
 
 
-- 
GitLab