diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..9d866e3
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: "pip" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml
new file mode 100644
index 0000000..e1e14af
--- /dev/null
+++ b/.github/workflows/pylint.yml
@@ -0,0 +1,24 @@
+name: Pylint
+
+on: [push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ["3.10"]
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v3
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+ pip install pylint
+ - name: Analysing the code with pylint
+ run: |
+ pylint --disable=C0114,C0115,C0116 --exit-zero $(git ls-files '*.py')
diff --git a/.gitignore b/.gitignore
index 08fdd16..e36b675 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,144 @@
+# Database files
database.db
-__pycache__
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+build/
+temp/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+Pipfile.lock
+
+# poetry
+poetry.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.env.*
+.venv
+venv/
+ENV/
+env/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# IDE settings
+.vscode/
+.idea/
\ No newline at end of file
diff --git a/.idea/Pilgrim.iml b/.idea/Pilgrim.iml
deleted file mode 100644
index 3defecc..0000000
--- a/.idea/Pilgrim.iml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 105ce2d..0000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index daedced..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
deleted file mode 100644
index 3586794..0000000
--- a/.idea/workspace.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1748985568579
-
-
- 1748985568579
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index d9baacb..7d8d17a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,50 @@
# Python_Pilgrim
-Python Based Travel Diary
\ No newline at end of file
+## Overview
+
+**Python_Pilgrim** is a Python-based travel diary application designed to help users document and manage their travel experiences. The project provides tools for recording trips, organizing travel notes, and storing memories in a structured and accessible format.
+
+## Features
+
+- Create and manage travel diaries
+- Add, edit, and delete travel entries
+- Organize trips by date, location, or theme
+- Store photos, notes, and other media
+- Export and share travel logs
+
+## Requirements
+- Python 3.8 or higher
+- Linux operating system (tested on Ubuntu 20.04+)
+- Visual Studio Code (VSCode) for development (optional but strongly recommended)
+- pip (Python package installer)
+- Optional: virtualenv for isolated environments
+
+## Installation
+
+1. Clone the repository:
+ ```bash
+ git clone https://github.com/gmbrax/Pilgrim.git
+ ```
+2. Navigate to the project directory:
+ ```bash
+ cd Pilgrim
+ ```
+3. Create a virtual environment and, then, activate it:
+ ```bash
+ python -m venv .venv
+ source .venv/bin/activate
+ ```
+4. Install the required dependencies:
+ ```bash
+ pip install -r requirements.txt
+ ```
+
+## Usage
+
+To run the main application, execute:
+
+```bash
+python ??>.py
+```
+
+This will start the Python_Pilgrim application. Follow the on-screen instructions to create and manage your travel diaries.
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 6f29a00..805875b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,6 +26,6 @@ src-layout = true
Homepage = "https://git.gustavomiranda.xyz/GHMiranda/Pilgrim"
Issues = "https://git.gustavomiranda.xyz/GHMiranda/Pilgrim"
[tool.hatch.build.targets.wheel]
-packages = ["src/Pilgrim"]
+packages = ["src/pilgrim"]
[project.scripts]
-pilgrim = "Pilgrim:main"
+pilgrim = "pilgrim:main"
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..182fec2
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+greenlet==3.2.3
+SQLAlchemy==2.0.41
+typing_extensions==4.14.0
\ No newline at end of file
diff --git a/src/Pilgrim/Application.py b/src/Pilgrim/Application.py
deleted file mode 100644
index 429798b..0000000
--- a/src/Pilgrim/Application.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from Pilgrim.Database import Database
-
-
-class Application:
- def __init__(self):
- self.database = Database()
-
- def run(self):
- self.database.create()
diff --git a/src/Pilgrim/TravelDiary.py b/src/Pilgrim/TravelDiary.py
deleted file mode 100644
index ea03940..0000000
--- a/src/Pilgrim/TravelDiary.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from sqlalchemy import Column, String, Integer
-
-from Pilgrim import Application, Base
-
-
-class TravelDiary(Base):
- __tablename__ = "TravelDiary"
- id = Column(Integer, primary_key=True)
- name = Column(String)
diff --git a/src/Pilgrim/__init__.py b/src/Pilgrim/__init__.py
deleted file mode 100644
index 201964a..0000000
--- a/src/Pilgrim/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from Pilgrim.Application import Application
-from Pilgrim.command import main
-from Pilgrim.Database import Database, Base
-from Pilgrim.TravelDiary import TravelDiary
-
-__all__ = ["Application", "Database", "TravelDiary", "main", "Base"]
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/application.py b/src/application.py
new file mode 100644
index 0000000..2dcb79a
--- /dev/null
+++ b/src/application.py
@@ -0,0 +1,16 @@
+from src.database import Database
+from src.service.servicemanager import ServiceManager
+
+
+class Application:
+ def __init__(self):
+ self.database = Database()
+
+ def run(self):
+ self.database.create()
+
+ def get_service_manager(self):
+ session = self.database.session()
+ session_manager = ServiceManager()
+ session_manager.set_session(session)
+ return session_manager
diff --git a/src/Pilgrim/command.py b/src/command.py
similarity index 56%
rename from src/Pilgrim/command.py
rename to src/command.py
index d132d04..3d23d5a 100644
--- a/src/Pilgrim/command.py
+++ b/src/command.py
@@ -1,4 +1,4 @@
-from Pilgrim import Application
+from src.application import Application
def main():
diff --git a/src/Pilgrim/Database.py b/src/database.py
similarity index 83%
rename from src/Pilgrim/Database.py
rename to src/database.py
index d28fdee..794d698 100644
--- a/src/Pilgrim/Database.py
+++ b/src/database.py
@@ -4,7 +4,6 @@ from sqlalchemy.orm import sessionmaker
Base = declarative_base()
-
class Database:
def __init__(self):
self.engine = create_engine(
@@ -12,10 +11,10 @@ class Database:
echo=False,
connect_args={"check_same_thread": False},
)
- self.Session = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)
+ self.session = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)
def create(self):
Base.metadata.create_all(self.engine)
def get_db(self):
- return self.Session()
+ return self.session()
diff --git a/src/models/__init__.py b/src/models/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/models/entry.py b/src/models/entry.py
new file mode 100644
index 0000000..8775faf
--- /dev/null
+++ b/src/models/entry.py
@@ -0,0 +1,26 @@
+from typing import Any
+
+from sqlalchemy import Column, Integer, String, ForeignKey
+from sqlalchemy.orm import relationship
+
+from src.models.photo_in_entry import photo_entry_association
+from src.database import Base
+
+
+class Entry(Base):
+ __tablename__ = "entries"
+ id = Column(Integer, primary_key=True)
+ title = Column(String)
+ text = Column(String)
+ date = Column(String)
+ photos = relationship(
+ "Photo",
+ secondary=photo_entry_association,
+ back_populates="entries")
+ fk_travel_diary_id = Column(Integer, ForeignKey("travel_diaries.id"),nullable=False)
+ def __init__(self, title: str, text: str, date: str, travel_diary_id: int, **kw: Any):
+ super().__init__(**kw)
+ self.title = title
+ self.text = text
+ self.date = date
+ self.fk_travel_diary_id = travel_diary_id
diff --git a/src/models/photo.py b/src/models/photo.py
new file mode 100644
index 0000000..d4eb6a9
--- /dev/null
+++ b/src/models/photo.py
@@ -0,0 +1,31 @@
+from typing import Any
+
+from sqlalchemy.orm import relationship
+from sqlalchemy import Column, Integer, String, ForeignKey
+
+from src.models.photo_in_entry import photo_entry_association
+from src.database import Base
+
+
+class Photo(Base):
+ __tablename__ = "photos"
+ id = Column(Integer, primary_key=True)
+ filepath = Column(String)
+ name = Column(String)
+ addition_date = Column(String)
+ caption = Column(String)
+ entries = relationship(
+ "Entry",
+ secondary=photo_entry_association,
+ back_populates="photos"
+ )
+
+ fk_travel_diary_id = Column(Integer, ForeignKey("travel_diaries.id"),nullable=False)
+
+ def __init__(self, filepath, name, addition_date=None, caption=None, entries=None, **kw: Any):
+ super().__init__(**kw)
+ self.filepath = filepath
+ self.name = name
+ self.addition_date = addition_date
+ self.caption = caption
+ self.entries = entries
diff --git a/src/models/photo_in_entry.py b/src/models/photo_in_entry.py
new file mode 100644
index 0000000..d07d4fa
--- /dev/null
+++ b/src/models/photo_in_entry.py
@@ -0,0 +1,8 @@
+from sqlalchemy import Table, Column, Integer, ForeignKey
+
+from src.database import Base
+
+photo_entry_association = Table('photo_entry_association', Base.metadata,
+Column('id', Integer, primary_key=True, autoincrement=True),
+ Column('fk_photo_id', Integer, ForeignKey('photos.id'),nullable=False),
+ Column('fk_entry_id', Integer, ForeignKey('entries.id'),nullable=False))
diff --git a/src/models/travel_diary.py b/src/models/travel_diary.py
new file mode 100644
index 0000000..15c8579
--- /dev/null
+++ b/src/models/travel_diary.py
@@ -0,0 +1,15 @@
+from typing import Any
+
+from src.database import Base
+
+from sqlalchemy import Column, String, Integer
+
+
+class TravelDiary(Base):
+ __tablename__ = "travel_diaries"
+ id = Column(Integer, primary_key=True)
+ name = Column(String)
+
+ def __init__(self, name: str, **kw: Any):
+ super().__init__(**kw)
+ self.name = name
diff --git a/src/service/__init__.py b/src/service/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/service/entry_service.py b/src/service/entry_service.py
new file mode 100644
index 0000000..2afedd0
--- /dev/null
+++ b/src/service/entry_service.py
@@ -0,0 +1,48 @@
+from typing import List
+
+from src.models.entry import Entry
+from src.models.travel_diary import TravelDiary
+
+
+class EntryService:
+ def __init__(self,session):
+ self.session = session
+
+ def create(self, travel_diary_id:int, title: str, text: str, date: str, ):
+ travel_diary = self.session.query(TravelDiary).filter(TravelDiary.id == travel_diary_id).first()
+ if not travel_diary:
+ return None
+ new_entry = Entry(title,text,date,travel_diary_id)
+ self.session.add(new_entry)
+ self.session.commit()
+ self.session.refresh(new_entry)
+ return new_entry
+
+ def read_by_id(self,entry_id:int)->Entry:
+ entry = self.session.query(Entry).filter(Entry.id == entry_id).first()
+ return entry
+
+ def read_all(self)-> List[Entry]:
+ entries = self.session.query(Entry).all()
+ return entries
+
+ def update(self,entry_src:Entry,entry_dst:Entry) -> Entry | None:
+ original:Entry = self.read_by_id(entry_src.id)
+ if original:
+ original.title = entry_dst.title
+ original.text = entry_dst.text
+ original.date = entry_dst.date
+ original.fk_travel_diary_id = entry_dst.fk_travel_diary_id
+ original.photos = entry_dst.photos
+ self.session.commit()
+ self.session.refresh(original)
+ return original
+ return None
+
+ def delete(self,entry_src:Entry)-> Entry | None:
+ excluded = self.read_by_id(entry_src.id)
+ if excluded is not None:
+ self.session.delete(excluded)
+ self.session.commit()
+ return excluded
+ return None
diff --git a/src/service/photo_service.py b/src/service/photo_service.py
new file mode 100644
index 0000000..2232ad1
--- /dev/null
+++ b/src/service/photo_service.py
@@ -0,0 +1,48 @@
+from pathlib import Path
+from typing import List
+
+from src.models.photo import Photo
+from src.models.travel_diary import TravelDiary
+
+
+class PhotoService:
+ def __init__(self, session):
+ self.session = session
+
+ def create(self, filepath:Path, name:str, travel_diary_id, addition_date=None, caption=None, ) -> Photo | None:
+ travel_diary = self.session.query(TravelDiary).filter(TravelDiary.id == travel_diary_id).first()
+ if not travel_diary:
+ return None
+ new_photo = Photo(filepath, name, addition_date=addition_date, caption=caption)
+ self.session.add(new_photo)
+ self.session.commit()
+ self.session.refresh(new_photo)
+
+ return new_photo
+ def read_by_id(self, photo_id:int) -> Photo:
+ return self.session.query(Photo).get(photo_id)
+
+ def read_all(self) -> List[Photo]:
+ return self.session.query(Photo).all()
+
+ def update(self,photo_src:Photo,photo_dst:Photo) -> Photo | None:
+ original:Photo = self.read_by_id(photo_src.id)
+ if original:
+ original.filepath = photo_dst.filepath
+ original.name = photo_dst.name
+ original.addition_date = photo_dst.addition_date
+ original.caption = photo_dst.caption
+ original.entries.extend(photo_dst.entries)
+ self.session.commit()
+ self.session.refresh(original)
+ return original
+ return None
+
+ def delete(self, photo_src:Photo) -> Photo | None:
+ excluded = self.read_by_id(photo_src.id)
+ if excluded:
+ self.session.delete(excluded)
+ self.session.commit()
+ self.session.refresh(excluded)
+ return excluded
+ return None
diff --git a/src/service/servicemanager.py b/src/service/servicemanager.py
new file mode 100644
index 0000000..3e9c3a6
--- /dev/null
+++ b/src/service/servicemanager.py
@@ -0,0 +1,19 @@
+from src.service.entry_service import EntryService
+from src.service.travel_diary_service import TravelDiaryService
+
+
+class ServiceManager:
+ def __init__(self):
+ self.session = None
+ def set_session(self, session):
+ self.session = session
+ def get_session(self):
+ return self.session
+ def get_entry_service(self):
+ if self.session is not None:
+ return EntryService(self.session)
+ return None
+ def get_travel_diary_service(self):
+ if self.session is not None:
+ return TravelDiaryService(self.session)
+ return None
diff --git a/src/service/travel_diary_service.py b/src/service/travel_diary_service.py
new file mode 100644
index 0000000..846f27d
--- /dev/null
+++ b/src/service/travel_diary_service.py
@@ -0,0 +1,35 @@
+from src.models.travel_diary import TravelDiary
+
+
+class TravelDiaryService:
+ def __init__(self,session):
+ self.session = session
+ def create(self, name:str):
+ new_travel_diary = TravelDiary(name)
+ self.session.add(new_travel_diary)
+ self.session.commit()
+ self.session.refresh(new_travel_diary)
+
+ return new_travel_diary
+
+ def read_by_id(self, travel_id:int):
+ return self.session.query(TravelDiary).get(travel_id)
+
+ def read_all(self):
+ return self.session.query(TravelDiary).all()
+
+ def update(self, travel_diary_src:TravelDiary,travel_diary_dst:TravelDiary):
+ original = self.read_by_id(travel_diary_src.id)
+ if original is not None:
+ original.name = travel_diary_dst.name
+ self.session.commit()
+ self.session.refresh(original)
+ return original
+
+ def delete(self, travel_diary_src:TravelDiary):
+ excluded = self.read_by_id(travel_diary_src.id)
+ if excluded is not None:
+ self.session.delete(travel_diary_src)
+ self.session.commit()
+ return excluded
+ return None