diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..6deafc2
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 120
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..888fa24
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,159 @@
+# 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/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+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/
+
+# PyCharm
+.idea/
+
+# Local test DB
+mapmakr.sqlite
diff --git a/mapmakr/app.py b/mapmakr/app.py
index 6fc2f5c..acd7804 100644
--- a/mapmakr/app.py
+++ b/mapmakr/app.py
@@ -1,15 +1,70 @@
from pathlib import Path
+from typing import List
-from fastapi import FastAPI
+from fastapi import Depends, FastAPI, HTTPException, Request, Response
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
+from fastapi.templating import Jinja2Templates
+from sqlmodel import Session, select
+
+from mapmakr.models import Marker, MarkerRead, MarkerCreate, MarkerUpdate, create_db_tables, \
+ get_session
+from mapmakr.settings import settings
+
ROOT = Path(__file__).parent
+
app = FastAPI()
-app.mount('/static', StaticFiles(directory='static'), name='static')
+app.mount('/static', StaticFiles(directory=str(ROOT / 'static')), name='static')
+templates = Jinja2Templates(directory=str(ROOT / 'templates'))
+
+
+@app.on_event('startup')
+def on_startup():
+ create_db_tables()
@app.get('/', response_class=HTMLResponse)
-async def index():
- content = (ROOT / 'templates' / 'index.html').open().read()
- return HTMLResponse(content=content, status_code=200)
+async def index(request: Request):
+ return templates.TemplateResponse('index.html', {'request': request,
+ 'site_title': settings.site_title})
+
+
+@app.post('/marker', tags=['markers'], response_model=MarkerRead)
+async def create_marker(marker: MarkerCreate, session: Session = Depends(get_session)) -> Marker:
+ db_marker = Marker.from_orm(marker)
+ session.add(db_marker)
+ session.commit()
+ session.refresh(db_marker)
+ return db_marker
+
+
+@app.patch('/marker/{marker_id}', tags=['markers'], response_model=MarkerRead)
+async def update_marker(marker_id: int, marker: MarkerUpdate,
+ session: Session = Depends(get_session)) -> Marker:
+ db_marker = session.get(Marker, marker_id)
+ if not db_marker:
+ raise HTTPException(status_code=404, detail='Marker not found')
+ marker_data = marker.dict(exclude_unset=True)
+ for key, value in marker_data.items():
+ setattr(db_marker, key, value)
+ session.add(db_marker)
+ session.commit()
+ session.refresh(db_marker)
+ return db_marker
+
+
+@app.get('/marker', tags=['markers'], response_model=List[MarkerRead])
+async def read_markers(session: Session = Depends(get_session)) -> list[MarkerRead]:
+ markers = session.exec(select(Marker)).all()
+ return markers
+
+
+@app.delete('/marker/{marker_id}', tags=['markers'])
+async def delete_marker(marker_id: int, session: Session = Depends(get_session)):
+ db_marker = session.get(Marker, marker_id)
+ if not db_marker:
+ raise HTTPException(status_code=404, detail='Marker not found')
+ session.delete(db_marker)
+ session.commit()
+ return Response(status_code=200)
diff --git a/mapmakr/database.py b/mapmakr/database.py
new file mode 100644
index 0000000..9d37ed0
--- /dev/null
+++ b/mapmakr/database.py
@@ -0,0 +1,12 @@
+from sqlmodel import create_engine
+
+from mapmakr.settings import settings
+
+_engine = None
+
+
+def get_engine():
+ global _engine
+ if not _engine:
+ _engine = create_engine(settings.database_uri, echo=settings.database_echo)
+ return _engine
diff --git a/mapmakr/models.py b/mapmakr/models.py
new file mode 100644
index 0000000..51e6abd
--- /dev/null
+++ b/mapmakr/models.py
@@ -0,0 +1,43 @@
+from decimal import Decimal
+from typing import Any, Dict, Optional
+
+from sqlalchemy.schema import Column
+from sqlalchemy.types import JSON
+from sqlmodel import Field, SQLModel, Session
+
+from mapmakr.database import get_engine
+
+
+class MarkerBase(SQLModel):
+ name: str
+ longitude: Decimal = Field(default=0)
+ latitude: Decimal = Field(default=0)
+ options: Dict[str, Any] = Field(sa_column=Column(JSON))
+
+
+class Marker(MarkerBase, table=True): # type: ignore[call-arg]
+ id: Optional[int] = Field(default=None, primary_key=True)
+
+
+class MarkerCreate(MarkerBase):
+ pass
+
+
+class MarkerRead(MarkerBase):
+ id: int
+
+
+class MarkerUpdate(SQLModel):
+ name: Optional[str] = None
+ longitude: Optional[Decimal] = None
+ latitude: Optional[Decimal] = None
+ options: Optional[Dict[str, Any]] = None
+
+
+def create_db_tables():
+ SQLModel.metadata.create_all(get_engine())
+
+
+def get_session():
+ with Session(get_engine()) as session:
+ yield session
diff --git a/mapmakr/settings.py b/mapmakr/settings.py
new file mode 100644
index 0000000..bbaab8e
--- /dev/null
+++ b/mapmakr/settings.py
@@ -0,0 +1,10 @@
+from pydantic import BaseSettings
+
+
+class Settings(BaseSettings):
+ database_uri: str = 'sqlite:///mapmakr.sqlite'
+ database_echo: bool = False
+ site_title: str = 'mapmakr'
+
+
+settings = Settings()
diff --git a/mapmakr/static/js/mapmakr.js b/mapmakr/static/js/mapmakr.js
index 87ddfb4..21ef09c 100644
--- a/mapmakr/static/js/mapmakr.js
+++ b/mapmakr/static/js/mapmakr.js
@@ -1,172 +1,136 @@
-/* */
+let map, drawnItems, drawControl;
-var map;
-var drawnItems;
-var statsControl;
-var drawControl;
-
-
-// http://stackoverflow.com/a/18324384/661150
-function callAjax(url, callback)
-{
- var xmlhttp;
- // compatible with IE7+, Firefox, Chrome, Opera, Safari
- xmlhttp = new XMLHttpRequest();
- xmlhttp.onreadystatechange = function(){
- if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
- callback(xmlhttp.responseText);
- }
- }
- xmlhttp.open("GET", url, true);
- xmlhttp.send();
-}
-
-
-function gitmap_reload() {
- callAjax("read.cgi", (function(req) {
- var map = window.map;
- drawnItems.clearLayers();
-
- var objects = JSON.parse(req).objects;
- var num_objects = objects.length;
- for (var i=0; i gitmap is a simple, small, 100% free/open-source, collaborative map
+ mapmakr is a simple, small, 100% free/open-source, collaborative map
editor that runs mostly in a web browser. It integrates community
FOSS projects and data sources.about gitmap
+about mapmakr
-FAQ
@@ -18,7 +18,7 @@ installation is for locating Red Hat remotees / offices. Other installations
may store whatever they like.
fche (gitmap integration scripts), +
fche (mapmakr integration scripts), Open Streetmap (background map), Leaflet (map rendering javascript library + plugins), and others.
@@ -55,7 +55,7 @@ Click on doomed markers. Click on "save" or "cancel".The front-end consists of very small HTML + JavaScript files that load Leaflet and OSM data from the Internet into your browser. The front-end also loads marker data from our own servers via HTTP CGI. @@ -77,8 +77,8 @@ the job, and easily.
Find gitmap sources -at https://gitlab.cee.redhat.com/fche/gitmap.git. +
Find mapmakr sources +at https://gitlab.cee.redhat.com/fche/mapmakr.git. One or two third-party javascript libraries are stored there; others are served from upstream projects' external CDNs. Feel free to fork / experiment / deploy. Send patches to fche if desired.
@@ -91,7 +91,7 @@ experiment / deploy. Send patches to fche if desired. Patches are welcome! -Please note that the version of the gitmap tree +
Please note that the version of the mapmakr tree in gitlab.cee contains snapshots of the real live personal data RH folks have chosen to share. It is obviously confidential.
diff --git a/mapmakr/templates/index.html b/mapmakr/templates/index.html index f7e9f57..b8cc5a6 100644 --- a/mapmakr/templates/index.html +++ b/mapmakr/templates/index.html @@ -1,30 +1,29 @@ -