diff --git a/memos/cmds/library.py b/memos/cmds/library.py index c529f80..1c62ba1 100644 --- a/memos/cmds/library.py +++ b/memos/cmds/library.py @@ -75,8 +75,14 @@ def ls(): @lib_app.command("create") def add(name: str, folders: List[str]): + absolute_folders = [] + for folder in folders: + folder_path = Path(folder).resolve() + absolute_folders.append({ + "path": str(folder_path), + "last_modified_at": datetime.fromtimestamp(folder_path.stat().st_mtime).isoformat(), + }) - absolute_folders = [str(Path(folder).resolve()) for folder in folders] response = httpx.post( f"{BASE_URL}/libraries", json={"name": name, "folders": absolute_folders}, @@ -89,7 +95,14 @@ def add(name: str, folders: List[str]): @lib_app.command("add-folder") def add_folder(library_id: int, folders: List[str]): - absolute_folders = [str(Path(folder).resolve()) for folder in folders] + absolute_folders = [] + for folder in folders: + folder_path = Path(folder).resolve() + absolute_folders.append({ + "path": str(folder_path), + "last_modified_at": datetime.fromtimestamp(folder_path.stat().st_mtime).isoformat(), + }) + response = httpx.post( f"{BASE_URL}/libraries/{library_id}/folders", json={"folders": absolute_folders}, diff --git a/memos/commands.py b/memos/commands.py index a4294d8..c447ff4 100644 --- a/memos/commands.py +++ b/memos/commands.py @@ -1,6 +1,7 @@ import os import logging from pathlib import Path +from datetime import datetime import httpx import typer @@ -97,9 +98,13 @@ def scan_default_library(force: bool = False): if not default_library["folders"]: # Add the screenshots directory to the library screenshots_dir = Path(settings.screenshots_dir).resolve() + folder = { + "path": str(screenshots_dir), + "last_modified_at": datetime.fromtimestamp(screenshots_dir.stat().st_mtime).isoformat(), + } response = httpx.post( f"{BASE_URL}/libraries/{default_library['id']}/folders", - json={"folders": [str(screenshots_dir)]}, + json={"folders": [folder]}, ) if response.status_code != 200: print( diff --git a/memos/crud.py b/memos/crud.py index bffef2d..3392731 100644 --- a/memos/crud.py +++ b/memos/crud.py @@ -37,8 +37,13 @@ def create_library(library: NewLibraryParam, db: Session) -> Library: db.commit() db.refresh(db_library) - for folder_path in library.folders: - db_folder = FolderModel(path=str(folder_path), library_id=db_library.id) + for folder in library.folders: + db_folder = FolderModel( + path=str(folder.path), + library_id=db_library.id, + last_modified_at=folder.last_modified_at, + type=folder.type, + ) db.add(db_folder) db.commit() @@ -46,7 +51,12 @@ def create_library(library: NewLibraryParam, db: Session) -> Library: id=db_library.id, name=db_library.name, folders=[ - Folder(id=db_folder.id, path=db_folder.path) + Folder( + id=db_folder.id, + path=db_folder.path, + last_modified_at=db_folder.last_modified_at, + type=db_folder.type, + ) for db_folder in db_library.folders ], plugins=[], @@ -66,13 +76,16 @@ def get_library_by_name(library_name: str, db: Session) -> Library | None: def add_folders(library_id: int, folders: NewFoldersParam, db: Session) -> Library: - db_folders = [] - for folder_path in folders.folders: - db_folder = FolderModel(path=str(folder_path), library_id=library_id) + for folder in folders.folders: + db_folder = FolderModel( + path=str(folder.path), + library_id=library_id, + last_modified_at=folder.last_modified_at, + type=folder.type, + ) db.add(db_folder) db.commit() db.refresh(db_folder) - db_folders.append(Folder(id=db_folder.id, path=db_folder.path)) db_library = db.query(LibraryModel).filter(LibraryModel.id == library_id).first() return Library(**db_library.__dict__) @@ -86,7 +99,9 @@ def create_entity(library_id: int, entity: NewEntityParam, db: Session) -> Entit entity.tags = None entity.metadata_entries = None - db_entity = EntityModel(**entity.model_dump(exclude_none=True), library_id=library_id) + db_entity = EntityModel( + **entity.model_dump(exclude_none=True), library_id=library_id + ) db.add(db_entity) db.commit() db.refresh(db_entity) @@ -371,14 +386,19 @@ def update_entity_metadata_entries( def get_plugin_by_id(plugin_id: int, db: Session) -> Plugin | None: return db.query(PluginModel).filter(PluginModel.id == plugin_id).first() + def remove_plugin_from_library(library_id: int, plugin_id: int, db: Session): - library_plugin = db.query(LibraryPluginModel).filter( - LibraryPluginModel.library_id == library_id, - LibraryPluginModel.plugin_id == plugin_id - ).first() - + library_plugin = ( + db.query(LibraryPluginModel) + .filter( + LibraryPluginModel.library_id == library_id, + LibraryPluginModel.plugin_id == plugin_id, + ) + .first() + ) + if library_plugin: db.delete(library_plugin) db.commit() else: - raise ValueError(f"Plugin {plugin_id} not found in library {library_id}") \ No newline at end of file + raise ValueError(f"Plugin {plugin_id} not found in library {library_id}") diff --git a/memos/models.py b/memos/models.py index 7f700f6..5d659d4 100644 --- a/memos/models.py +++ b/memos/models.py @@ -13,7 +13,7 @@ from sqlalchemy import ( from datetime import datetime from sqlalchemy.orm import relationship, DeclarativeBase, Mapped, mapped_column, Session from typing import List -from .schemas import MetadataSource, MetadataType +from .schemas import MetadataSource, MetadataType, FolderType from sqlalchemy.exc import OperationalError from sqlalchemy.orm import sessionmaker from .config import get_database_path, settings @@ -52,6 +52,12 @@ class FolderModel(Base): entities: Mapped[List["EntityModel"]] = relationship( "EntityModel", back_populates="folder" ) + type: Mapped[FolderType] = mapped_column( + Enum(FolderType), nullable=False + ) + last_modified_at: Mapped[datetime | None] = mapped_column( + DateTime, nullable=False + ) class EntityModel(Base): diff --git a/memos/schemas.py b/memos/schemas.py index b1b6042..c406733 100644 --- a/memos/schemas.py +++ b/memos/schemas.py @@ -11,6 +11,11 @@ from datetime import datetime from enum import Enum +class FolderType(Enum): + DEFAULT = "default" + DUMMY = "dummy" + + class MetadataSource(Enum): USER_GENERATED = "user_generated" SYSTEM_GENERATED = "system_generated" @@ -23,17 +28,19 @@ class MetadataType(Enum): NUMBER_DATA = "number" -class NewLibraryParam(BaseModel): - name: str - folders: List[DirectoryPath] = [] - - class NewFolderParam(BaseModel): path: DirectoryPath + last_modified_at: datetime + type: str = FolderType.DEFAULT + + +class NewLibraryParam(BaseModel): + name: str + folders: List[NewFolderParam] = [] class NewFoldersParam(BaseModel): - folders: List[DirectoryPath] = [] + folders: List[NewFolderParam] = [] class EntityMetadataParam(BaseModel): @@ -103,6 +110,8 @@ class NewLibraryPluginParam(BaseModel): class Folder(BaseModel): id: int path: str + last_modified_at: datetime + type: FolderType model_config = ConfigDict(from_attributes=True) diff --git a/memos/server.py b/memos/server.py index f40982e..13f2e99 100644 --- a/memos/server.py +++ b/memos/server.py @@ -146,8 +146,14 @@ def new_library(library_param: NewLibraryParam, db: Session = Depends(get_db)): ) # Remove duplicate folders from the library_param - unique_folders = list(set(library_param.folders)) + unique_folders = [] + seen_paths = set() + for folder in library_param.folders: + if folder.path not in seen_paths: + seen_paths.add(folder.path) + unique_folders.append(folder) library_param.folders = unique_folders + library = crud.create_library(library_param, db) return library